home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / gcore / sun4.md / gcore.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-02  |  14.7 KB  |  523 lines

  1. /* 
  2.  * gcore.c --
  3.  *
  4.  *    This file contains a program that will produce a Unix
  5.  *    style core dump of a process.
  6.  *    See the man page for details on what it does.
  7.  *
  8.  * Copyright 1988 Regents of the University of California
  9.  * Permission to use, copy, modify, and distribute this
  10.  * software and its documentation for any purpose and without
  11.  * fee is hereby granted, provided that the above copyright
  12.  * notice appear in all copies.  The University of California
  13.  * makes no representations about the suitability of this
  14.  * software for any purpose.  It is provided "as is" without
  15.  * express or implied warranty.
  16.  */
  17.  
  18. #ifndef lint
  19. static char rcsid[] = "$Header: /sprite/src/cmds/gcore/RCS/gcore.c,v 1.3 91/10/25 10:28:35 jhh Exp $ SPRITE (Berkeley)";
  20. #endif not lint
  21.  
  22. #include <ctype.h>
  23. #include <option.h>
  24. #include <status.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <signal.h>
  29. #include <sys/types.h>
  30. #include <sys/file.h>
  31. #include <kernel/proc.h>
  32. #include <a.out.h>
  33. #include <errno.h>
  34.  
  35. extern char *sys_errlist[];
  36.  
  37. #include "gcore.h"
  38.  
  39.  
  40. Boolean    debug = FALSE;            /* Output debugging info. */
  41. char    *outFilePrefix = "core";    /* Coredump output file. */
  42. #ifdef SAFETY
  43. Boolean    dumpRunningProcess = FALSE;    /* If true, an attempt is made to
  44.                      * dump process not in the debugger.
  45.                      */
  46. #else
  47. Boolean    dumpRunningProcess = TRUE;    /* If true, an attempt is made to
  48.                      * dump process not in the debugger.
  49.                      */
  50. #endif    
  51.  
  52. int    debugSignal = SIGTRAP;        /* Signal to bump process into the
  53.                      * debugger with.
  54.                      */
  55. Boolean killProcess = FALSE;        /* Kill process after dump. */
  56.  
  57. Option optionArray[] = {
  58.    {OPT_DOC,    (char *) NULL,    (char *) NULL,
  59.         "This program generates a core dump of a process.\n Synopsis:  \"gcore [options] pid [pid pid...]\"\nOptions are:"},
  60.    {OPT_STRING, "o", (char *) &outFilePrefix, "Prefix string for dump files."},
  61. #ifdef SAFETY
  62.    {OPT_TRUE,   "f", (char *) &dumpRunningProcess, 
  63.     "The dump the process evening if it is running."},
  64. #endif
  65.    {OPT_TRUE,   "k", (char *) &killProcess, "Kill processes after the dump."},  
  66.    {OPT_INT,    "s", (char *) &debugSignal, "Signal number to stop processes."},
  67.    {OPT_TRUE,    "d", (char *) &debug, "Output program debugging info."},
  68. };
  69.  
  70. /*
  71.  * Forward procedure declarations.
  72.  */
  73. static Boolean    DumpCore();
  74.  
  75.  
  76. /*
  77.  *----------------------------------------------------------------------
  78.  *
  79.  * main --
  80.  *
  81.  *    The main program for gcore.
  82.  *
  83.  * Results:
  84.  *    None.
  85.  *
  86.  * Side effects:
  87.  *    Writes output to sepcified file.
  88.  *
  89.  *----------------------------------------------------------------------
  90.  */
  91.  
  92. main(argc, argv)
  93.     int argc;        /* Number of command-line arguments. */
  94.     char **argv;    /* Values of command-line arguments. */
  95. {
  96.     int numCantDump;
  97.     int    i;
  98.  
  99.     argc = Opt_Parse(argc, argv, optionArray, Opt_Number(optionArray),0);
  100.     if (argc < 2) {
  101.     (void) fprintf(stderr,"Usage: %s [options] pid ...\n",PROGRAM_NAME);
  102.     exit(1);
  103.     } 
  104.     if (debug) {
  105.       fprintf (stderr,"Here we go...\n");
  106.     }
  107.     numCantDump = 0;
  108.     for (i = 1; i < argc; i++) {
  109.         int    pid;
  110.     char    *pidString;
  111.     char    *outFileName = malloc(strlen(outFilePrefix)+16);
  112.  
  113.     pidString = argv[i];
  114.     if (debug) {
  115.       fprintf (stderr,"PID: %s\n", pidString);
  116.     }
  117.         /*
  118.      * Convert the string pidString into an integer pid.
  119.      */
  120.     {
  121.         char    *endPtr;
  122.  
  123.         pid = strtoul(pidString, &endPtr, 16);
  124.         if (endPtr == pidString) {
  125.         (void) fprintf(stderr,"%s: Bad process id \"%s\"; ignoring\n", 
  126.             PROGRAM_NAME,  pidString);
  127.         numCantDump++;
  128.         continue;
  129.         }
  130.     
  131.     }
  132.     (void) sprintf(outFileName,"%s.%s",outFilePrefix,pidString);
  133.     if (debug) {
  134.       fprintf (stderr,"Dumping core...\n");
  135.     }
  136.         if (DumpCore(pid, outFileName, pidString)) {
  137.         (void) printf("%s: %s dumped\n",PROGRAM_NAME,outFileName);
  138.     } else {
  139.         numCantDump++;
  140.     }
  141.     }
  142.     exit(numCantDump);
  143. }
  144.  
  145.  
  146.  
  147. /*
  148.  *----------------------------------------------------------------------
  149.  *
  150.  * GetProgramName --
  151.  *
  152.  *    Find the program name in the command string.
  153.  *
  154.  *    The routine takes a command string and returns the name of the 
  155.  *    program used in the command.  A command is assume to be a string
  156.  *    of the form:
  157.  *        commandPathname    arg1 arg2 arg3 ....
  158.  *    The program name is the file name of the exec file in the command.
  159.  *
  160.  * Results:
  161.  *    Nothing.
  162.  *
  163.  * Side effects:
  164.  *      None.
  165.  *
  166.  *----------------------------------------------------------------------
  167.  */
  168.  
  169. void 
  170. GetProgramName(argString,programName)
  171.     char    *argString;    /* Argument string of process. */
  172.     char    *programName;    /* Area to place program name. */
  173. {
  174.     register char    *endPtr, *startPtr;
  175.  
  176.     /*
  177.      * Strip any leading blanks.
  178.      */
  179.     while (*argString == ' ') {
  180.     argString++;
  181.     }
  182.     /*
  183.      * Locate the end of the program string. This is either the first blank
  184.      * or end of string.
  185.      */
  186.     endPtr = strchr(argString,' ');
  187.     if (endPtr == NULL) {
  188.     endPtr = argString + strlen(argString);
  189.     }
  190.     if (endPtr == argString) {
  191.     *programName = 0;
  192.     return;
  193.     }
  194.     /*
  195.      * From the end of the program string, find the beginning by working 
  196.      * backwards until the first '/' or beginning of string is found.
  197.      */
  198.     for (startPtr = endPtr - 1; startPtr > argString; startPtr--) {
  199.     if (*startPtr == '/') {
  200.         startPtr++;
  201.         break;
  202.     }
  203.     }
  204.     { 
  205.     int    len = endPtr - startPtr;
  206.     bcopy(startPtr, programName, len);
  207.     programName[len] = 0;
  208.     }
  209. }
  210.  
  211.  
  212.  
  213. /*
  214.  *----------------------------------------------------------------------
  215.  *
  216.  *  DumpCore --
  217.  *
  218.  *      Dump the core image of the specified process.
  219.  *
  220.  * Results:
  221.  *    True if dump succeeded, false otherwise.
  222.  *
  223.  * Side effects:
  224.  *      Core image is dumped to a file.
  225.  *
  226.  *----------------------------------------------------------------------
  227.  */
  228. static Boolean
  229. DumpCore(pid,coreFileName,pidString)
  230.     int     pid;            /* Process id to dump. */
  231.     char     *coreFileName;    /* Name of core file to create. */
  232.     char    *pidString;    /* String name of pid - use only for message. */
  233. {
  234.     char        *argString;    /* Argument string of process. */
  235.     char        *argStringProgram;
  236.     struct core        coreHeader;    /* Header written to coreFile. */
  237.     int            segSize[NUM_SEGMENTS];
  238.     FILE        *coreFile;    /* Core file. */
  239.     int            procState, procOrigState;
  240.     int            sigState;
  241.     Boolean        retVal = FALSE;
  242.     ProcExecHeader  header;
  243.    /*
  244.     * Find the status and argument string of the process. 
  245.     */
  246.  
  247.     argString = malloc(MAX_ARG_STRING_SIZE);
  248.     /*
  249.      * Find and record the original state of this process. 
  250.      */
  251.     sigState = debugSignal;
  252.     procOrigState = FindProcess(pid,argString,segSize,&sigState);
  253.  
  254.     if (procOrigState == NOT_FOUND_STATE) {
  255.      (void) fprintf(stderr, "%s: Process id %s not found.\n",
  256.             PROGRAM_NAME, pidString );
  257.     return (FALSE);
  258.     }
  259.     /*
  260.      * Insure that we can open the coreFile before signalling the process.
  261.      */
  262.     if (debug) {
  263.       fprintf (stderr,"Opening core file and putting process in debug state...\n");
  264.     }
  265.     coreFile = fopen(coreFileName,"w");
  266.     if (coreFile == (FILE *) NULL) {
  267.       (void) fprintf(stderr,
  268.              "%s: Can't open %s: %s\n",PROGRAM_NAME,coreFileName,
  269.              sys_errlist[errno]);
  270.       return (FALSE);
  271.     }
  272.     /*
  273.      * If the process is not already in the DEBUG state, put it there.
  274.      */
  275.     if (procOrigState != DEBUG_STATE) {
  276.     /*
  277.      * Check to see if SAFETY is on.
  278.      */
  279.     if (!dumpRunningProcess) {
  280.         (void) fprintf(stderr,
  281.         "%s: Process id %s is running, must use -f to dump.\n",
  282.         PROGRAM_NAME, pidString);
  283.         (void) fclose(coreFile); (void) unlink(coreFileName);
  284.         return (FALSE);
  285.     }
  286.     /*
  287.      * See if the debugSignal is being held, ignored, or handled.
  288.      */
  289.     if (sigState != 0) {
  290.         char    *problem;
  291.  
  292.         if (sigState & SIG_IGNORING) {
  293.         problem = "ignoring";
  294.         } else if (sigState & SIG_HANDLING) {
  295.         problem = "handling";
  296.         } else if (sigState & SIG_HOLDING) {
  297.         problem = "holding";
  298.         } else {
  299.         problem = NULL;
  300.         }
  301.         if (problem) { 
  302.         (void) fprintf(stderr,
  303.             "%s: Process %s is %s signal %d; can't dump.\n",
  304.             PROGRAM_NAME, pidString, problem, debugSignal);
  305.         (void) fclose(coreFile); (void) unlink(coreFileName);
  306.         return (FALSE);
  307.         }
  308.     }
  309.     /*
  310.      * Try bumping the process into the debugger. This will fail if the
  311.      * user can't signal the process.
  312.      */
  313.     if(kill(pid,debugSignal) < 0) {
  314.         (void) fprintf(stderr,
  315.             "%s: Can't signal process %s with signal %d: %s\n",
  316.             PROGRAM_NAME, pidString, debugSignal,sys_errlist[errno]);
  317.         (void) fclose(coreFile); (void) unlink(coreFileName);
  318.         return (FALSE);
  319.      } 
  320.      (void) sleep(1);
  321.      procState = FindProcess(pid,argString,segSize,(int *) 0);
  322.      /* 
  323.       * If process is still not in the debug state, trying giving it a
  324.       * SIGCONT.  This appears to be necessary to get suspended process
  325.       * into the debug state.
  326.       */
  327.      if (procState == SUSPEND_STATE) {
  328.         (void) kill(pid,SIGCONT);
  329.             (void) sleep(1);
  330.         procState = FindProcess(pid,argString,segSize,(int *) 0);
  331.      }
  332.      if (procState != DEBUG_STATE) {
  333.          if (procState == NOT_FOUND_STATE) {
  334.         (void) fprintf(stderr,
  335.             "%s: Process id %s disappeared after signal %d, sorry.\n",
  336.             PROGRAM_NAME, pidString,debugSignal);
  337.         } else {
  338.         (void) fprintf(stderr,
  339.             "%s: Process %s wont stop for signal %d.\n",
  340.             PROGRAM_NAME, pidString, debugSignal);
  341.         }
  342.         (void) fclose(coreFile); (void) unlink(coreFileName);
  343.         return (FALSE);
  344.     }
  345.     }
  346.     /*
  347.      * Attach the process using the debugger interface. 
  348.      */
  349.     if (debug) {
  350.       fprintf (stderr,"Attaching to process...\n");
  351.     }
  352.     if (!AttachProcess(pid)) {
  353.     (void) fprintf(stderr,
  354.            "%s: Can't attach process %s\n",PROGRAM_NAME, pidString);
  355.     (void) fclose(coreFile); (void) unlink(coreFileName);
  356.     return(FALSE);
  357.     }
  358.  
  359.     /* Find the program name from the argument string. */
  360.  
  361.     argStringProgram = malloc(strlen(argString)+1);
  362.     GetProgramName(argString,argStringProgram);
  363.     if (debug) {
  364.       fprintf (stderr,"Program name: %s\n", argStringProgram);
  365.     }
  366.     /*
  367.      * Fill in the core file header with our best guess.
  368.      */
  369.      coreHeader.c_magic = CORE_MAGIC;
  370.      coreHeader.c_len = sizeof(struct core);
  371.      if (!ReadStopInfoFromProcess(pid,&coreHeader.c_signo,&coreHeader.c_regs)) {
  372.      (void) fprintf(stderr,
  373.             "%s: Can't read regs of process %s\n",PROGRAM_NAME,
  374.             pidString);
  375.      (void) fclose(coreFile); 
  376.      goto errout;
  377.      }
  378.      if (debug) {
  379.        fprintf (stderr,"Signal: %d\nSP: %d\nPC: %d\n", coreHeader.c_signo, coreHeader.c_regs.r_sp, coreHeader.c_regs.r_pc);
  380.      }
  381.      /*
  382.       * Fill in the exec file header with our best guesses.
  383.       */
  384.      bzero((char *)&coreHeader.c_aouthdr,sizeof(coreHeader.c_aouthdr));
  385.      coreHeader.c_aouthdr.a_magic = ZMAGIC;
  386.      coreHeader.c_aouthdr.a_text = segSize[TEXT_SEG];
  387.      coreHeader.c_aouthdr.a_data = segSize[DATA_SEG];
  388.  
  389.      coreHeader.c_tsize = coreHeader.c_aouthdr.a_text;
  390.      if (debug) {
  391.        fprintf (stderr,"Text Size: %d\n", coreHeader.c_tsize);
  392.      }
  393.      (void) strncpy(coreHeader.c_cmdname,argStringProgram,CORE_NAMELEN);
  394.  
  395.      /*
  396.       * Write empty coreHeader to be filled in later. This reserve space
  397.       * in the output file for the header.
  398.       */
  399.      if (debug) {
  400.        fprintf (stderr,"Writing empty core header...\n");
  401.      }
  402.      if (fwrite((char *)&coreHeader,sizeof(coreHeader),1,coreFile) != 1) {
  403.      (void) fprintf(stderr,"%s: Can't write file %s: %s\n",PROGRAM_NAME,
  404.         coreFileName,sys_errlist[errno]);
  405.      (void) fclose(coreFile);
  406.      goto errout;
  407.      }
  408.  
  409.     /*
  410.      * Follow the coreHeader with the data segment
  411.      */
  412.      {
  413.        if (debug) {
  414.      fprintf (stderr,"Getting data segment...\n");
  415.        }
  416.        bcopy((char *)&coreHeader.c_aouthdr,(char *)&header, sizeof(header));
  417.        coreHeader.c_dsize = XferSegmentFromProcess(pid,
  418.          (unsigned int) PROC_DATA_LOAD_ADDR(header),coreFile);
  419.      }
  420.      if (debug) {
  421.        fprintf (stderr,"Data Size: %d\n", coreHeader.c_dsize);
  422.      }
  423.      if (coreHeader.c_dsize <= 0) {
  424.      (void) fprintf(stderr,"%s: Can't read data segment.\n",PROGRAM_NAME);
  425.      (void) fclose(coreFile);
  426.      goto errout;
  427.      }
  428.  
  429.     /*
  430.      * And then the stack segment starting with at the stack pointer.
  431.      */
  432.        if (debug) {
  433.      fprintf (stderr,"Getting stack segment...\n");
  434.        }
  435.      coreHeader.c_ssize = XferSegmentFromProcess(pid,
  436.                    (unsigned int) coreHeader.c_regs.r_sp, coreFile);
  437.      if (debug) {
  438.        fprintf (stderr,"Stack Size: %d\n", coreHeader.c_ssize);
  439.      }
  440.      if (coreHeader.c_ssize <= 0) {
  441.      (void) fprintf(stderr,"%s: Can't read stack segment.\n",PROGRAM_NAME);
  442.      (void) fclose(coreFile);
  443.      goto errout;
  444.      }
  445.      /*
  446.       * Now rewrite the coreFile header with the new data and stack segment
  447.       * sizes.
  448.       */
  449.      if (fseek(coreFile,0,0) < 0) {
  450.      (void) fprintf(stderr,
  451.         "%s: Can't rewrite file %s header: %s\n",PROGRAM_NAME,
  452.         coreFileName,sys_errlist[errno]);
  453.      }
  454.      if (debug) {
  455.        fprintf (stderr,"Before rewrite...\nSignal: %d\nSP: %d\nPC: %d\n", coreHeader.c_signo, coreHeader.c_regs.r_sp, coreHeader.c_regs.r_pc);
  456.        fprintf (stderr,"Rewriting header...\n");
  457.      }
  458.      if (fwrite((char *)&coreHeader,sizeof(coreHeader),1,coreFile) != 1) {
  459.      (void) fprintf(stderr,"%s: Can't write %s : %s\n",PROGRAM_NAME,
  460.         coreFileName,sys_errlist[errno]);
  461.      (void) fclose(coreFile);
  462.      goto errout;
  463.      }
  464.      if (fclose(coreFile) != 0)  {
  465.      (void) fprintf(stderr,"%s: Error closing %s : %s\n",PROGRAM_NAME,
  466.         coreFileName,sys_errlist[errno]);
  467.      }
  468.     if (debug) {
  469.        fprintf (stderr,"Core file closed, go home.\n");
  470.      }
  471.      retVal = TRUE;
  472.      /* 
  473.       * Did the user want the process dead?
  474.       */
  475.      if (killProcess && (kill(pid,SIGKILL) < 0)) {
  476.      (void) fprintf(stderr,
  477.             "%s: Can't kill process %s: %s\n",
  478.             PROGRAM_NAME, pidString, sys_errlist[errno]);
  479.      }
  480.  errout:
  481.      /*
  482.       * Detach the debugger from the process. If the process was in
  483.       * the suspend state the detach will start it running again. 
  484.       * The current thinking is that this is not good so we leave
  485.       * suspended processes in the debugger.
  486.       */
  487.      if (killProcess || ! ( (procOrigState == SUSPEND_STATE) ||
  488.                 (procOrigState == DEBUG_STATE))) {
  489.      static char *procStateNames[] = STATE_NAMES;
  490.      (void) DetachProcess(pid);
  491.      (void) sleep(1);
  492.      procState = FindProcess(pid,argString,(int *) 0,(int *) 0);
  493.      /*
  494.       * If we didn't want it dead and it died?
  495.       */
  496.      if (!killProcess && (procState == NOT_FOUND_STATE)) {
  497.         (void) fprintf(stderr,
  498.         "%s: Warning: Process %s disappeared after dump, sorry.\n",
  499.         PROGRAM_NAME, pidString);
  500.      } else if (killProcess && (procState != NOT_FOUND_STATE)) {
  501. #ifdef notdef
  502.     /*
  503.      * This doesn't appear to work.
  504.      */
  505.         (void) fprintf(stderr,
  506.         "%s: Warning: Process %s didn't die.\n",PROGRAM_NAME, 
  507.          pidString);
  508. #endif
  509.      } else if (procState != procOrigState) {
  510.          (void) fprintf(stderr,
  511.         "%s: Warning: Process %s new state is %s was %s\n",
  512.         PROGRAM_NAME, pidString,procStateNames[procState],
  513.         procStateNames[procOrigState]);
  514.      } 
  515.      }
  516.      if (!retVal) {
  517.      (void) unlink(coreFileName);
  518.      (void) fclose(coreFile);
  519.      }
  520.      return (retVal);
  521. }
  522.  
  523.